package com.lovezy.platform.member.service.impl;

import com.lovezy.platform.core.base.enums.FrontEnum;
import com.lovezy.platform.core.base.enums.StatusEnum;
import com.lovezy.platform.core.base.query.Pager;
import com.lovezy.platform.core.base.service.MapperService;
import com.lovezy.platform.core.codec.CodecUtil;
import com.lovezy.platform.core.exception.ServiceException;
import com.lovezy.platform.core.exception.ValidationException;
import com.lovezy.platform.core.valid.ValidatorUtil;
import com.lovezy.platform.discuz.model.DiscuzMember;
import com.lovezy.platform.filestore.model.File;
import com.lovezy.platform.filestore.service.FileService;
import com.lovezy.platform.member.enums.EmailStatusEnum;
import com.lovezy.platform.member.exception.MemberExceptionEnum;
import com.lovezy.platform.member.form.EditProfileForm;
import com.lovezy.platform.member.mapper.MemberMapper;
import com.lovezy.platform.member.model.Member;
import com.lovezy.platform.member.model.MemberExample;
import com.lovezy.platform.member.service.CheckMemberDataResult;
import com.lovezy.platform.member.service.MemberService;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Consumer;

import static com.lovezy.platform.member.exception.MemberExceptionEnum.MEMBER_NOT_FOUND;
import static com.lovezy.platform.member.exception.MemberExceptionEnum.OLD_PASSWORD_WRONG;
import static com.lovezy.platform.member.form.EditProfileForm.EDIT_AVATAR;
import static com.lovezy.platform.member.form.EditProfileForm.EDIT_NICKNAME;
import static com.lovezy.platform.member.form.EditProfileForm.EDIT_PASSWORD;
import static java.util.stream.Collectors.toList;

/**
 * 用户实现
 * Created by jin on 2017/11/5.
 */
@Service
public class MemberServiceImpl extends MapperService<Member,String,MemberMapper>implements MemberService{

    @Autowired
    private FileService fileService;

    private final Object emailCheckLock = new Object();
    private final Object usernameCheckLock = new Object();

    @Override
    public Optional<Member> findDiscuzMember(@NotNull Integer dzId) {
        MemberExample example = new MemberExample();
        MemberExample.Criteria criteria = example.createCriteria();
        criteria.andDzIdEqualTo(dzId);
        return Pager.doSingleton(() -> mapper.selectByExample(example));
    }

    @Override
    public Member addMember(Member member) {
        return doAddMember(member, null);
    }

    @Override
    public Member addMemberForOtherSystem(Member member, Consumer<Member> beforeSave) {
        return doAddMember(member, beforeSave);
    }

    @Override
    public Member findByMemberId(@NotNull String mid) {
        MemberExample example = new MemberExample();
        example.createCriteria()
                .andMemberIdEqualTo(mid)
                .andStatusEqualTo(StatusEnum.NORMAL.value());
        Optional<Member> dbMemberOpt = Pager.doSingleton(() -> mapper.selectByExample(example));
        if (!dbMemberOpt.isPresent()) {
            throw new ServiceException(MEMBER_NOT_FOUND.getErrorCode(), MEMBER_NOT_FOUND.getErrorMsg());
        }
        return dbMemberOpt.get();
    }

    @Override
    public List<String> findNames(List<String> mids) {
        return mids.stream()
                .map(id -> mapper.selectByPrimaryKey(id))
                .filter(Objects::nonNull)
                .map(Member::getNickname)
                .collect(toList());
    }

    @Override
    public Optional<Member> findByMobile(@NotNull String mobile) {
        MemberExample example = new MemberExample();
        example.createCriteria().andMobileEqualTo(mobile).andStatusEqualTo(StatusEnum.NORMAL.value());
        return Pager.doSingleton(() -> mapper.selectByExample(example));
    }

    @Override
    public Member findByUserNameAndPassword(String loginName, String password) {
        MemberExample example = new MemberExample();
        example.createCriteria()
                .andMobileEqualTo(loginName)
                .andStatusEqualTo(StatusEnum.NORMAL.value());
        Optional<Member> dbMemberOpt = Pager.doSingleton(() -> mapper.selectByExample(example));
        if (!dbMemberOpt.isPresent()) {
            throw new ServiceException(MEMBER_NOT_FOUND.getErrorCode(), MEMBER_NOT_FOUND.getErrorMsg());
        }
        Member member = dbMemberOpt.get();
        String salt = member.getSalt();
        String realPassword = password + salt;
        realPassword = CodecUtil.md5(realPassword);
        if (!realPassword.equals(member.getPassword())) {
            throw new ValidationException(MemberExceptionEnum.MEMBER_PASSWORD_WRONG.getErrorCode(), MemberExceptionEnum.MEMBER_PASSWORD_WRONG.getErrorMsg());
        }
        return member;
    }

    @Override
    public void editPassword(@NotNull EditProfileForm form) {
        ValidatorUtil.validateAlias(form,EDIT_PASSWORD);
        Member m = mapper.selectByPrimaryKey(form.getMemberId());
        if (m == null) {
            throw new ServiceException(MEMBER_NOT_FOUND.getErrorCode(), MEMBER_NOT_FOUND.getErrorMsg());
        }
        String salt = m.getSalt();
        String oldPassword = m.getPassword();
        String newPassword = form.getNewPassword();

        // 如果有密码 需要校验原密码
        if (StringUtils.hasText(oldPassword)) {
            String formOldPassword = CodecUtil.md5(form.getOldPassword() + salt);
            if (!formOldPassword.equals(oldPassword)) {
                throw new ServiceException(OLD_PASSWORD_WRONG.getErrorCode(), OLD_PASSWORD_WRONG.getErrorMsg());
            }
        }
        if (salt == null) {
            salt = CodecUtil.randomDigit(6);
        }
        newPassword = CodecUtil.md5(newPassword + salt);
        Member updateMember = new Member();
        String memberId = m.getMemberId();
        updateMember.setMemberId(memberId);
        updateMember.setPassword(newPassword);
        updateMember.setGmtModify(new Date());
        updateMember.setSalt(salt);
        mapper.updateByPrimaryKeySelective(updateMember);

        tokenInvalid(memberId);
    }


    @Override
    public void resetPassword(String mid, String password) {
        Member m = mapper.selectByPrimaryKey(mid);
        if (m == null) {
            throw new ServiceException(MEMBER_NOT_FOUND.getErrorCode(), MEMBER_NOT_FOUND.getErrorMsg());
        }
        String salt = m.getSalt();
        String newPassword = CodecUtil.md5(password + salt);
        Member updateMember = new Member();
        updateMember.setMemberId(mid);
        updateMember.setPassword(newPassword);
        updateMember.setGmtModify(new Date());
        mapper.updateByPrimaryKeySelective(updateMember);
    }

    @Override
    public void editAvatar(EditProfileForm form) {
        ValidatorUtil.validateAlias(form, EDIT_AVATAR);
        String url = form.getAvatar();
        File avatarFile = fileService.findFileByUrl(url);
        Member m = new Member();
        m.setMemberId(form.getMemberId());
        m.setAvatar(avatarFile.getFileId());
        m.setGmtModify(new Date());
        mapper.updateByPrimaryKeySelective(m);
    }

    @Override
    public void editNickname(EditProfileForm form) {
        ValidatorUtil.validate(form, EDIT_NICKNAME);
        Member m = new Member();
        m.setNickname(form.getNickname());
        m.setMemberId(form.getMemberId());
        m.setGmtModify(new Date());
        mapper.updateByPrimaryKeySelective(m);
    }

    @Override
    public void tokenInvalid(@NotNull String memberId) {
        Member m = new Member();
        m.setMemberId(memberId);
        m.setToken("");
        m.setMobileToken("");
        mapper.updateByPrimaryKeySelective(m);
    }

    @Override
    public Optional<Member> findMemberByToken(String token, FrontEnum front) {
        MemberExample example = new MemberExample();
        MemberExample.Criteria criteria = example.createCriteria()
                .andStatusEqualTo(StatusEnum.NORMAL.value());
        if (front == FrontEnum.WEB) {
            criteria.andTokenEqualTo(token);
        }else {
            criteria.andMobileTokenEqualTo(token);
        }
        return Pager.doSingleton(() -> mapper.selectByExample(example));
    }

    /**
     * TODO 有啥作用
     * @param dzMember
     * @return
     */
    public Member addMemberForDiscuz(DiscuzMember dzMember) {
        Member member = new Member();
        member.setMemberId(CodecUtil.uuid());
        member.setDzId(dzMember.getUid());
        member.setUsername(dzMember.getUsername());
        member.setPassword(dzMember.getPassword());
        member.setSalt(dzMember.getSalt());
        member.setEmail(member.getEmail());
        CheckMemberDataResult checkResult = checkUniqueData(member);
        if (!checkResult.isResult()) {
            throw new ValidationException(MemberExceptionEnum.VALID_MEMBER_INFO_IS_EXISTS.getErrorCode(), checkResult.getMsg());
        }
        mapper.insertSelective(member);
        return member;
    }

    private Member doAddMember(Member member, Consumer<Member> beforeSave) {
        CheckMemberDataResult checkResult = checkUniqueData(member);
        if (!checkResult.isResult()) {
            throw new ValidationException(MemberExceptionEnum.VALID_MEMBER_INFO_IS_EXISTS.getErrorCode(), checkResult.getMsg());
        }
        member.setMemberId(CodecUtil.uuid());

        if (StringUtils.hasText(member.getPassword())) {
            String salt = CodecUtil.randomDigit(6);
            member.setSalt(salt);
            member.setPassword(CodecUtil.md5(member.getPassword() + salt));
        }

        Date now = new Date();
        member.setRegDate(now);
        member.setGmtModify(now);

        if (beforeSave != null) {
            beforeSave.accept(member);
        }
        mapper.insertSelective(member);
        return member;
    }

    private CheckMemberDataResult checkUniqueData(Member member) {
        String email = member.getEmail();
        String username = member.getUsername();
        String mobile = member.getMobile();
        if (email != null) {
            MemberExample example = new MemberExample();
            example.createCriteria()
                    .andEmailEqualTo(email)
                    .andEmailStatusEqualTo(EmailStatusEnum.AUTHENTICATED.value())
                    .andStatusEqualTo(StatusEnum.NORMAL.value());
            CheckMemberDataResult checkResult = check(example, emailCheckLock, "邮箱已被注册！");
            if (!checkResult.isResult()) {
                return checkResult;
            }
        }
        if (mobile != null) {
            MemberExample example = new MemberExample();
            example.createCriteria()
                    .andMobileEqualTo(mobile)
                    .andStatusEqualTo(StatusEnum.NORMAL.value());
            CheckMemberDataResult checkResult = check(example, usernameCheckLock, "手机号已被注册！");
            if (!checkResult.isResult()) {
                return checkResult;
            }
        }
        return CheckMemberDataResult.SUCCESS;

    }

    private CheckMemberDataResult check(MemberExample example,Object lockObject,String msg) {
        synchronized (lockObject) {
            Optional<Member> member = Pager.doSingleton(() -> mapper.selectByExample(example));
            if (member.isPresent()) {
                return new CheckMemberDataResult(false, msg);
            }
        }
        return CheckMemberDataResult.SUCCESS;

    }



}
